package com.wujunshen.dumpling.maven.plugin.mojo;

import com.wujunshen.dumpling.common.utils.FileUtils;
import com.wujunshen.dumpling.core.Configuration;
import com.wujunshen.dumpling.core.engine.EngineConfig;
import com.wujunshen.dumpling.core.engine.EngineFileType;
import com.wujunshen.dumpling.core.engine.EngineTemplateType;
import com.wujunshen.dumpling.core.execute.DocumentationExecute;
import com.wujunshen.dumpling.core.process.ProcessConfig;
import com.wujunshen.dumpling.database.query.DataBaseType;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import lombok.Data;
import lombok.EqualsAndHashCode;
import org.apache.commons.lang3.StringUtils;
import org.apache.maven.plugin.AbstractMojo;
import org.apache.maven.plugin.MojoFailureException;
import org.apache.maven.plugins.annotations.LifecyclePhase;
import org.apache.maven.plugins.annotations.Mojo;
import org.apache.maven.plugins.annotations.Parameter;

import javax.sql.DataSource;
import java.util.List;

import static com.wujunshen.dumpling.common.constant.Constants.NAME;
import static com.wujunshen.dumpling.common.constant.Constants.USE_INFORMATION_SCHEMA;
import static com.wujunshen.dumpling.common.utils.FileUtils.getRealFilePath;
import static com.wujunshen.dumpling.core.query.DataBaseQueryFactory.getDbType;

/** @author frankwoo */
@EqualsAndHashCode(callSuper = true)
@Data
@Mojo(name = "run", threadSafe = true, defaultPhase = LifecyclePhase.COMPILE)
public class RunDocMojo extends AbstractMojo {
  // ====================基本配置====================//
  /** 组织 */
  @Parameter(property = "organization")
  private String organization;
  /** url */
  @Parameter(property = "organizationUrl")
  private String organizationUrl;
  /** 标题 */
  @Parameter(property = "title")
  private String title;
  /** 版本 */
  @Parameter(property = "version")
  private String version;
  /** 描述 */
  @Parameter(property = "description")
  private String description;

  // ====================连接配置====================//
  /** 用户名 */
  @Parameter private volatile String userName;
  /** 密码 */
  @Parameter private volatile String password;

  /** 驱动类名称 */
  @Parameter private String driverClassName;
  /** JDBC URL */
  @Parameter private String jdbcUrl;

  // ====================数据处理配置====================//
  /** 忽略表名 */
  @Parameter private List<String> ignoreTableName;
  /** 忽略表前缀 */
  @Parameter private List<String> ignoreTablePrefix;
  /** 忽略表后缀 */
  @Parameter private List<String> ignoreTableSuffix;
  /** 指定生成表名 */
  @Parameter private List<String> designatedTableName;
  /** 指定生成表前缀 */
  @Parameter private List<String> designatedTablePrefix;
  /** 指定生成表后缀 */
  @Parameter private List<String> designatedTableSuffix;

  // ====================生成引擎配置====================//
  /** 是否打开输出目录 */
  @Parameter(defaultValue = "false")
  private boolean openOutputDir;
  /** 文件产生位置 */
  @Parameter private String fileOutputDir;
  /** 生成文件类型 */
  @Parameter(defaultValue = "html")
  private EngineFileType fileType;
  /** 生成实现 */
  @Parameter(defaultValue = "freemarker")
  private EngineTemplateType produceType;
  /** 自定义模板，模板需要和文件类型和使用模板的语法进行编写和处理，否则将会生成错误 */
  @Parameter private String template;
  /** 文件名称 */
  @Parameter private String fileName;

  /** 文档生成 */
  @Override
  public void execute() throws MojoFailureException {
    // 参数为空
    validator();
    // 总配置
    Configuration config =
        Configuration.builder()
            // 组织
            .organization(getOrganization())
            // url
            .organizationUrl(getOrganizationUrl())
            // 标题
            .title(getTitle())
            // 版本
            .version(getVersion())
            // 描述
            .description(getDescription())
            // 数据源
            .dataSource(getDataSource())
            // 引擎模板配置
            .engineConfig(getEngineConfig())
            // 数据处理配置
            .produceConfig(getProcessConfig())
            .build();
    // 生成文档
    new DocumentationExecute(config).execute();
  }

  /** 引擎模板配置 */
  private EngineConfig getEngineConfig() {
    return EngineConfig.builder()
        // 是否打开目录
        .openOutputDir(isOpenOutputDir())
        // 生成文件路径
        .fileOutputDir(getFileOutputDir())
        // 文件类型
        .fileType(getFileType())
        // 生成模板实现
        .produceType(getProduceType())
        // 自定义模板位置
        .customTemplate(getTemplate())
        // 文件名称
        .fileName(getFileName())
        .build();
  }

  /** 数据处理配置 */
  private ProcessConfig getProcessConfig() {
    return ProcessConfig.builder()
        // 忽略表名
        .ignoreTableName(getIgnoreTableName())
        // 忽略表前缀
        .ignoreTablePrefix(getIgnoreTablePrefix())
        // 忽略表后缀
        .ignoreTableSuffix(getIgnoreTableSuffix())
        // 指定生成表名
        .designatedTableName(getDesignatedTableName())
        // 指定生成表前缀
        .designatedTablePrefix(getDesignatedTablePrefix())
        // 指定生成表后缀
        .designatedTableSuffix(getDesignatedTableSuffix())
        .build();
  }

  /** 获取数据源 */
  private DataSource getDataSource() {
    HikariConfig hikariConfig = new HikariConfig();
    hikariConfig.setPoolName(NAME);
    // 驱动名称
    hikariConfig.setDriverClassName(getDriverClassName().trim());
    // url
    hikariConfig.setJdbcUrl(getJdbcUrl());
    // 用户名
    hikariConfig.setUsername(getUserName());
    // 密码
    hikariConfig.setPassword(getPassword());
    // mysql
    if (getDbType(getJdbcUrl()).equals(DataBaseType.MYSQL)) {
      hikariConfig.addDataSourceProperty(USE_INFORMATION_SCHEMA, "true");
    }
    return new HikariDataSource(hikariConfig);
  }

  /** 参数验证 */
  private void validator() throws MojoFailureException {
    // 基础配置验证
    if (StringUtils.isBlank(getUserName())) {
      throw new MojoFailureException("请配置数据库用户名");
    }
    if (StringUtils.isBlank(getDriverClassName())) {
      throw new MojoFailureException("请配置数据库驱动名");
    }
    if (StringUtils.isBlank(getJdbcUrl())) {
      throw new MojoFailureException("请配置数据库地址");
    }
    // 验证模板是否存在
    if (StringUtils.isNotBlank(getTemplate())) {
      String path = getRealFilePath(getTemplate());
      boolean exists = FileUtils.isFileExists(path);
      if (!exists) {
        throw new MojoFailureException("未检索到模板文件[" + path + "]");
      }
    }
  }
}
